<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CBD商超物联网设备监控中心</title>
    <!-- 引入外部资源 -->
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>

    <!-- 配置Tailwind自定义颜色 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#165DFF',
                        secondary: '#36CFC9',
                        success: '#00B42A',
                        danger: '#F53F3F',
                        warning: '#FF7D00',
                        info: '#86909C'
                    }
                }
            }
        }
    </script>

    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .card-shadow {
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
            }
            .device-card-hover {
                transition: all 0.3s ease;
            }
            .device-card-hover:hover {
                transform: translateY(-4px);
                box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
            }
            .status-indicator {
                width: 10px;
                height: 10px;
                border-radius: 50%;
                display: inline-block;
            }
            .animate-fadeIn {
                animation: fadeIn 0.5s ease-in-out;
            }
            @keyframes fadeIn {
                from { opacity: 0; }
                to { opacity: 1; }
            }
        }
    </style>
</head>

<body class="bg-gray-50 min-h-screen font-sans">
    <!-- 登录页面（默认显示） -->
    <div id="login-page" class="flex items-center justify-center min-h-screen bg-gray-100 p-4">
        <div class="w-full max-w-md bg-white rounded-xl shadow-md overflow-hidden">
            <div class="bg-primary p-6 text-center">
                <i class="fa fa-cogs text-white text-4xl mb-3"></i>
                <h2 class="text-xl font-bold text-white">CBD商超物联网设备监控中心</h2>
                <p class="text-white/80 text-sm mt-1">请登录后查看设备数据</p>
            </div>
            <div class="p-6">
                <form id="login-form" class="space-y-4">
                    <div>
                        <label for="username" class="block text-sm font-medium text-gray-700 mb-1">用户名</label>
                        <div class="relative">
                            <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                                <i class="fa fa-user text-gray-400"></i>
                            </div>
                            <input type="text" id="username" name="username" value="admin"
                                class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-lg focus:ring-primary focus:border-primary outline-none transition-colors"
                                required>
                        </div>
                    </div>
                    <div>
                        <label for="password" class="block text-sm font-medium text-gray-700 mb-1">密码</label>
                        <div class="relative">
                            <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                                <i class="fa fa-lock text-gray-400"></i>
                            </div>
                            <input type="password" id="password" name="password" value="admin"
                                class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-lg focus:ring-primary focus:border-primary outline-none transition-colors"
                                required>
                        </div>
                    </div>
                    <div id="login-error" class="hidden text-danger text-sm text-center py-2">
                        <i class="fa fa-exclamation-circle mr-1"></i>
                        <span>用户名或密码错误，请重试</span>
                    </div>
                    <button type="submit"
                        class="w-full bg-primary text-white py-2 px-4 rounded-lg hover:bg-primary/90 transition-colors flex items-center justify-center">
                        <i class="fa fa-sign-in mr-2"></i>
                        <span>登录</span>
                    </button>
                </form>
            </div>
        </div>
    </div>

    <!-- 主监控页面（默认隐藏） -->
    <div id="control-page" class="hidden">
        <!-- 顶部导航栏 -->
        <header class="bg-white shadow-sm fixed top-0 left-0 right-0 z-30">
            <div class="container mx-auto px-4 py-3 flex justify-between items-center">
                <div class="flex items-center">
                    <i class="fa fa-cogs text-primary text-xl mr-2"></i>
                    <h1 class="text-lg font-bold text-gray-800">CBD商超物联网设备监控中心</h1>
                </div>

                <div class="flex items-center space-x-6">
                    <div class="hidden md:flex items-center text-sm text-gray-600">
                        <i class="fa fa-clock-o mr-1"></i>
                        <span id="current-time">--:--:--</span>
                    </div>

                    <div class="flex items-center">
                        <span id="user-info" class="hidden md:inline-block mr-2 text-sm font-medium">
                            <i class="fa fa-user-circle mr-1"></i>
                            <span id="current-username">管理员</span>
                        </span>
                        <button id="logout-btn" class="text-gray-500 hover:text-danger transition-colors duration-300">
                            <i class="fa fa-sign-out"></i>
                            <span class="hidden md:inline-block ml-1">退出</span>
                        </button>
                    </div>
                </div>
            </div>
        </header>

        <!-- 系统状态概览 -->
        <div class="bg-primary text-white py-2 mt-16">
            <div class="container mx-auto px-4">
                <div class="flex flex-wrap items-center justify-between">
                    <div class="flex items-center mb-2 md:mb-0">
                        <i class="fa fa-server mr-2"></i>
                        <span>系统状态: </span>
                        <span id="system-status-indicator"
                            class="ml-2 px-2 py-0.5 bg-success/20 text-success text-xs rounded-full flex items-center">
                            <span class="w-1.5 h-1.5 bg-success rounded-full mr-1 animate-pulse"></span>
                            正常运行中
                        </span>
                    </div>
                    <div class="text-xs text-white/80">
                        协议版本: v1.0 | MQTT服务器: <span id="mqtt-server-status">未连接</span> | 数据更新间隔: 3秒
                    </div>
                </div>
            </div>
        </div>

        <!-- 主内容区 -->
        <main class="container mx-auto px-4 py-6">
            <!-- 快速状态卡片 -->
            <section class="my-6 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
                <div class="bg-white rounded-xl p-4 shadow-sm device-card-hover">
                    <div class="flex justify-between items-start">
                        <div>
                            <p class="text-gray-500 text-sm">在线设备</p>
                            <p class="text-2xl font-bold mt-1 text-success" id="online-devices">0</p>
                            <p class="text-xs text-gray-500 mt-1">共<span id="total-devices">0</span>台设备</p>
                        </div>
                        <div class="w-10 h-10 rounded-full bg-success/10 flex items-center justify-center text-success">
                            <i class="fa fa-plug"></i>
                        </div>
                    </div>
                </div>

                <div class="bg-white rounded-xl p-4 shadow-sm device-card-hover">
                    <div class="flex justify-between items-start">
                        <div>
                            <p class="text-gray-500 text-sm">当前温度</p>
                            <p class="text-2xl font-bold mt-1 text-primary" id="current-temp">--.-°C</p>
                            <p class="text-xs text-gray-500 mt-1">来自温度传感器</p>
                        </div>
                        <div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary">
                            <i class="fa fa-thermometer-half"></i>
                        </div>
                    </div>
                </div>

                <div class="bg-white rounded-xl p-4 shadow-sm device-card-hover">
                    <div class="flex justify-between items-start">
                        <div>
                            <p class="text-gray-500 text-sm">当前湿度</p>
                            <p class="text-2xl font-bold mt-1 text-secondary" id="current-humidity">--%</p>
                            <p class="text-xs text-gray-500 mt-1">来自湿度传感器</p>
                        </div>
                        <div class="w-10 h-10 rounded-full bg-secondary/10 flex items-center justify-center text-secondary">
                            <i class="fa fa-tint"></i>
                        </div>
                    </div>
                </div>

                <div class="bg-white rounded-xl p-4 shadow-sm device-card-hover">
                    <div class="flex justify-between items-start">
                        <div>
                            <p class="text-gray-500 text-sm">警报状态</p>
                            <p class="text-2xl font-bold mt-1 text-success" id="alarm-status">正常</p>
                            <p class="text-xs text-gray-500 mt-1">无异常情况</p>
                        </div>
                        <div class="w-10 h-10 rounded-full bg-success/10 flex items-center justify-center text-success">
                            <i class="fa fa-bell-o"></i>
                        </div>
                    </div>
                </div>
            </section>

            <!-- 温湿度趋势图和监控画面 -->
            <section class="my-6 grid grid-cols-1 lg:grid-cols-2 gap-6">
                <div class="bg-white rounded-xl p-5 shadow-sm">
                    <div class="flex justify-between items-center mb-4">
                        <h2 class="text-lg font-bold text-gray-800">温湿度趋势图</h2>
                        <div class="flex space-x-2">
                            <button class="time-filter px-3 py-1 text-xs bg-primary text-white rounded-full"
                                data-range="hour">1小时</button>
                            <button
                                class="time-filter px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-full transition-all duration-300"
                                data-range="day">24小时</button>
                            <button
                                class="time-filter px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-full transition-all duration-300"
                                data-range="week">7天</button>
                        </div>
                    </div>
                    <div id="temp-humidity-chart" class="w-full h-[300px]"></div>
                </div>

                <!-- 监控画面 (集成mjpg-streamer) -->
                <div class="bg-white rounded-xl p-5 shadow-sm">
                    <div class="flex justify-between items-center mb-4">
                        <h2 class="text-lg font-bold text-gray-800">实时监控</h2>
                        <div class="flex items-center space-x-3">
                            <span class="text-xs text-gray-500 flex items-center">
                                <span class="status-indicator bg-success mr-1"></span>
                                <span id="monitor-status">连接中...</span>
                            </span>
                            <button id="refresh-monitor" class="text-primary text-sm flex items-center hover:underline">
                                <i class="fa fa-refresh mr-1"></i>
                                <span>刷新</span>
                            </button>
                        </div>
                    </div>
                    <div class="relative bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
                        <!-- 集成mjpg-streamer的监控画面 -->
                        <iframe id="monitor-iframe" src="http://192.168.243.1:8080/stream_simple.html" title="实时监控画面"
                            class="w-full h-[300px] border-0" onload="monitorLoaded()"
                            onerror="monitorError()"></iframe>

                        <!-- 加载状态遮罩 -->
                        <div id="monitor-loading"
                            class="absolute inset-0 bg-gray-200/80 flex items-center justify-center">
                            <div class="text-center">
                                <i class="fa fa-circle-o-notch fa-spin text-2xl text-gray-600 mb-2"></i>
                                <p class="text-sm text-gray-600">监控画面加载中...</p>
                            </div>
                        </div>

                        <div class="absolute bottom-2 left-2 bg-black/50 text-white text-xs px-2 py-1 rounded">
                            <i class="fa fa-clock-o mr-1"></i>
                            <span id="monitor-timestamp">--:--:--</span>
                        </div>
                    </div>

                    <!-- 监控设备切换 -->
                    <div class="grid grid-cols-3 gap-2 mt-3 text-xs">
                        <button class="monitor-camera-btn bg-primary text-white p-2 rounded" data-camera="1"
                            data-url="http://192.168.243.1:8080/stream_simple.html">
                            <p>摄像头1</p>
                            <p>仓库区域</p>
                        </button>
                        <button
                            class="monitor-camera-btn bg-gray-50 text-gray-800 p-2 rounded hover:bg-gray-100 transition-colors"
                            data-camera="2" data-url="http://192.168.0.120:8080/stream_simple.html">
                            <p>摄像头2</p>
                            <p>设备区域</p>
                        </button>
                        <button
                            class="monitor-camera-btn bg-gray-50 text-gray-800 p-2 rounded hover:bg-gray-100 transition-colors"
                            data-camera="3" data-url="http://对方设备IP:8080/stream_simple.html">
                            <p>摄像头3</p>
                            <p>入口区域</p>
                        </button>
                    </div>
                </div>
            </section>

            <!-- 设备监控选项卡（无控制按钮） -->
            <section class="my-6">
                <div class="bg-white rounded-xl shadow-sm overflow-hidden">
                    <!-- 选项卡导航 -->
                    <div class="border-b border-gray-200">
                        <div class="flex overflow-x-auto">
                            <button
                                class="device-tab py-4 px-6 text-primary border-b-2 border-primary font-medium whitespace-nowrap"
                                data-tab="stm32">
                                STM32 设备
                            </button>
                            <button
                                class="device-tab py-4 px-6 text-gray-500 hover:text-gray-700 border-b-2 border-transparent whitespace-nowrap"
                                data-tab="modbus">
                                Modbus 设备
                            </button>
                            <button
                                class="device-tab py-4 px-6 text-gray-500 hover:text-gray-700 border-b-2 border-transparent whitespace-nowrap"
                                data-tab="metaServer">
                                元服务器设备
                            </button>
                        </div>
                    </div>

                    <!-- STM32设备监控区 -->
                    <div class="device-content p-5" id="stm32-content">
                        <h2 class="text-lg font-bold text-gray-800 mb-4">STM32 设备状态</h2>
                        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5" id="stm32-devices-container">
                            <div class="text-center py-10 text-gray-500">
                                <i class="fa fa-circle-o-notch fa-spin text-2xl mb-2"></i>
                                <p>加载设备数据中...</p>
                            </div>
                        </div>
                    </div>

                    <!-- Modbus设备监控区 -->
                    <div class="device-content p-5 hidden" id="modbus-content">
                        <h2 class="text-lg font-bold text-gray-800 mb-4">Modbus 设备状态</h2>
                        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5" id="modbus-devices-container">
                            <div class="text-center py-10 text-gray-500">
                                <i class="fa fa-circle-o-notch fa-spin text-2xl mb-2"></i>
                                <p>加载设备数据中...</p>
                            </div>
                        </div>
                    </div>

                    <!-- 元服务器设备监控区 -->
                    <div class="device-content p-5 hidden" id="metaServer-content">
                        <h2 class="text-lg font-bold text-gray-800 mb-4">元服务器设备状态</h2>
                        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5"
                            id="metaServer-devices-container">
                            <div class="text-center py-10 text-gray-500">
                                <i class="fa fa-circle-o-notch fa-spin text-2xl mb-2"></i>
                                <p>加载设备数据中...</p>
                            </div>
                        </div>
                    </div>
                </div>
            </section>

            <!-- 操作日志 -->
            <section class="my-6">
                <div class="bg-white rounded-xl p-5 shadow-sm">
                    <h2 class="text-lg font-bold text-gray-800 mb-4">系统日志</h2>
                    <div class="overflow-x-auto max-h-[200px] overflow-y-auto pr-2" id="operation-log">
                        <div class="text-sm text-gray-500 mb-2">
                            <span class="text-gray-400">[--:--:--]</span> 系统初始化完成
                        </div>
                    </div>
                </div>
            </section>
        </main>

        <!-- 页脚 -->
        <footer class="bg-white border-t border-gray-200 py-4 mt-auto">
            <div class="container mx-auto px-4 text-center text-gray-500 text-sm">
                <p>CBD商超物联网设备监控中心 &copy; 2025</p>
                <p class="mt-1">协议版本: v1.0 | 数据每3秒自动更新</p>
            </div>
        </footer>
    </div>

    <!-- 通知提示组件 -->
    <div id="notification"
        class="fixed top-4 right-4 bg-white shadow-lg rounded-lg p-4 transform translate-x-full transition-all duration-300 flex items-center max-w-xs z-50">
        <div id="notification-icon"
            class="w-8 h-8 rounded-full flex items-center justify-center mr-3 bg-success/10 text-success">
            <i class="fa fa-check"></i>
        </div>
        <div>
            <h4 id="notification-title" class="font-medium text-gray-800">操作成功</h4>
            <p id="notification-message" class="text-sm text-gray-500 mt-1">设备数据更新成功</p>
        </div>
        <button id="close-notification" class="ml-4 text-gray-400 hover:text-gray-600">
            <i class="fa fa-times"></i>
        </button>
    </div>

    <script>
        // 全局变量 - 初始化设备默认点表（与共享内存结构一致）
        let tempHumidityChart = null;
        let deviceData = {
            stm32: {
                data: [
                    { key: 1001, name: "冷藏柜", type: 2, typeStata: 2, value: 0, floatValue: 0 },
                    { key: 1002, name: "电源插座", type: 2, typeStata: 2, value: 0, floatValue: 0 },
                    { key: 1003, name: "门锁", type: 2, typeStata: 2, value: 0, floatValue: 0 },
                    { key: 1004, name: "排风扇", type: 2, typeStata: 2, value: 0, floatValue: 0 },
                    { key: 1005, name: "灯光状态", type: 2, typeStata: 2, value: 0, floatValue: 0 },
                    { key: 1006, name: "温度传感器", type: 3, typeStata: 0, value: 0, floatValue: 0.00000000 },
                    { key: 1007, name: "湿度传感器", type: 3, typeStata: 0, value: 0, floatValue: 0.0000000 },
                    { key: 1008, name: "险情警报", type: 2, typeStata: 2, value: 0, floatValue: 0 }
                ]
            },
            modbus: { data: [] },
            metaServer: { data: [] }
        };
        let updateInterval = null;
        const API_BASE_URL = ''; // 服务器API基础路径（与共享内存接口一致）

        // 设备名称与图标映射
        const deviceNameIcons = {
            '冷藏柜': 'fa-snowflake-o',
            '电源插座': 'fa-power-off',
            '门锁': 'fa-lock',
            '排风扇': 'fa-fan',
            '灯光状态': 'fa-lightbulb-o',
            '温度传感器': 'fa-thermometer-half',
            '湿度传感器': 'fa-tint',
            '险情警报': 'fa-exclamation-triangle',      
            '空调模式': 'fa-snowflake-o',
            '窗帘控制': 'fa-columns',
            '窗户控制': 'fa-window-maximize',
            '商超广告大屏': 'fa-television',
            '水产水量控制': 'fa-tint',
            '空调电源状态': 'fa-power-off',
            '人体红外检测': 'fa-user-secret',
            '烟感控制': 'fa-fire-extinguisher',
            '遮阳板控制': 'fa-umbrella',
            '通风设计': 'fa-wind',
            '灯光控制': 'fa-lightbulb-o',
            '收银台钱锁控制': 'fa-lock',
            '安检设备控制': 'fa-shield'
        };

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function () {
            // 登录表单提交事件
            document.getElementById('login-form').addEventListener('submit', function (e) {
                e.preventDefault();
                const username = document.getElementById('username').value.trim();
                const password = document.getElementById('password').value.trim();

                // 验证账号密码（均为admin）
                if (username === 'admin' && password === 'admin') {
                    // 登录成功：存储用户信息，切换到监控页面
                    localStorage.setItem('usr_user_name', 'admin');
                    showControlPage();
                    logOperation('管理员登录成功');
                } else {
                    // 登录失败：显示错误提示
                    document.getElementById('login-error').classList.remove('hidden');
                    setTimeout(() => {
                        document.getElementById('login-error').classList.add('hidden');
                    }, 3000);
                }
            });

            // 登出按钮事件
            document.getElementById('logout-btn').addEventListener('click', handleLogout);

            // 关闭通知
            document.getElementById('close-notification').addEventListener('click', hideNotification);

            // 设备选项卡切换
            document.querySelectorAll('.device-tab').forEach(tab => {
                tab.addEventListener('click', function () {
                    // 切换选项卡样式
                    document.querySelectorAll('.device-tab').forEach(t => {
                        t.classList.remove('text-primary', 'border-primary');
                        t.classList.add('text-gray-500', 'border-transparent');
                    });
                    this.classList.remove('text-gray-500', 'border-transparent');
                    this.classList.add('text-primary', 'border-primary');

                    // 切换内容显示
                    const tabName = this.getAttribute('data-tab');
                    document.querySelectorAll('.device-content').forEach(content => {
                        content.classList.add('hidden');
                    });
                    document.getElementById(`${tabName}-content`).classList.remove('hidden');
                });
            });

            // 时间过滤器
            document.querySelectorAll('.time-filter').forEach(filter => {
                filter.addEventListener('click', function () {
                    document.querySelectorAll('.time-filter').forEach(f => {
                        f.classList.remove('bg-primary', 'text-white');
                        f.classList.add('bg-gray-100', 'hover:bg-gray-200');
                    });
                    this.classList.remove('bg-gray-100', 'hover:bg-gray-200');
                    this.classList.add('bg-primary', 'text-white');
                    updateChartData(this.getAttribute('data-range'));
                });
            });

            // 刷新监控画面
            document.getElementById('refresh-monitor').addEventListener('click', refreshMonitor);

            // 监控摄像头切换
            document.querySelectorAll('.monitor-camera-btn').forEach(btn => {
                btn.addEventListener('click', function () {
                    document.querySelectorAll('.monitor-camera-btn').forEach(b => {
                        b.classList.remove('bg-primary', 'text-white');
                        b.classList.add('bg-gray-50', 'text-gray-800');
                    });
                    this.classList.remove('bg-gray-50', 'text-gray-800');
                    this.classList.add('bg-primary', 'text-white');
                    const cameraUrl = this.getAttribute('data-url');
                    switchCamera(cameraUrl);
                });
            });

            // 检查是否已登录（页面刷新时）
            if (localStorage.getItem('usr_user_name')) {
                showControlPage();
            }
        });

        // 显示监控页面，隐藏登录页面
        function showControlPage() {
            document.getElementById('login-page').classList.add('hidden');
            document.getElementById('control-page').classList.remove('hidden');
            document.getElementById('current-username').textContent = '管理员';
            initControlPage();
        }

        // 初始化监控页面
        function initControlPage() {
            initTimeDisplay();
            initChart();
            fetchDeviceData(); // 加载共享内存数据
            startDataUpdate(); // 启动定时更新
        }

        // 处理登出
        function handleLogout() {
            localStorage.removeItem('usr_user_name');
            if (updateInterval) {
                clearInterval(updateInterval);
                updateInterval = null;
            }
            document.getElementById('control-page').classList.add('hidden');
            document.getElementById('login-page').classList.remove('hidden');
            logOperation('管理员退出登录');
        }

        // 初始化时间显示
        function initTimeDisplay() {
            function updateTime() {
                const now = new Date();
                const timeStr = now.toTimeString().slice(0, 8);
                document.getElementById('current-time').textContent = timeStr;
                document.getElementById('monitor-timestamp').textContent = timeStr;
            }
            updateTime();
            setInterval(updateTime, 1000);
        }

        // 初始化温湿度图表
        function initChart() {
            const chartDom = document.getElementById('temp-humidity-chart');
            tempHumidityChart = echarts.init(chartDom);
            const initialData = generateTimeSeriesData(60); // 1小时初始数据

            const option = {
                tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } },
                legend: { data: ['温度(°C)', '湿度(%)'], top: 0 },
                grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
                xAxis: { type: 'category', boundaryGap: false, data: initialData.times },
                yAxis: [
                    { type: 'value', name: '温度(°C)', min: 15, max: 35, axisLine: { color: '#165DFF' } },
                    { type: 'value', name: '湿度(%)', min: 30, max: 80, axisLine: { color: '#36CFC9' }, position: 'right' }
                ],
                series: [
                    {
                        name: '温度(°C)',
                        type: 'line',
                        data: initialData.temps,
                        symbol: 'none',
                        lineStyle: { width: 2, color: '#165DFF' },
                        areaStyle: {
                            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                                { offset: 0, color: 'rgba(22, 93, 255, 0.2)' },
                                { offset: 1, color: 'rgba(22, 93, 255, 0)' }
                            ])
                        }
                    },
                    {
                        name: '湿度(%)',
                        type: 'line',
                        yAxisIndex: 1,
                        data: initialData.humis,
                        symbol: 'none',
                        lineStyle: { width: 2, color: '#36CFC9' },
                        areaStyle: {
                            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                                { offset: 0, color: 'rgba(54, 207, 201, 0.2)' },
                                { offset: 1, color: 'rgba(54, 207, 201, 0)' }
                            ])
                        }
                    }
                ]
            };
            tempHumidityChart.setOption(option);
            window.addEventListener('resize', () => tempHumidityChart.resize());
        }

        // 生成时间序列数据
        function generateTimeSeriesData(points) {
            const times = [];
            const temps = [];
            const humis = [];
            const now = new Date();

            for (let i = points - 1; i >= 0; i--) {
                const time = new Date(now - i * 60 * 1000);
                const hour = time.getHours().toString().padStart(2, '0');
                const minute = time.getMinutes().toString().padStart(2, '0');
                times.push(`${hour}:${minute}`);

                // 初始模拟数据（后续会被共享内存数据覆盖）
                const baseTemp = 25;
                temps.push((baseTemp + (Math.random() * 4 - 2)).toFixed(1));
                const baseHumi = 50;
                humis.push((baseHumi + (Math.random() * 20 - 10)).toFixed(0));
            }
            return { times, temps, humis };
        }

        // 更新图表数据
        function updateChartData(range) {
            let points = 60;
            if (range === 'day') points = 24;
            else if (range === 'week') points = 7;
            const newData = generateTimeSeriesData(points);
            tempHumidityChart.setOption({
                xAxis: { data: newData.times },
                series: [{ data: newData.temps }, { data: newData.humis }]
            });
        }

        // 定时加载共享内存数据
        function startDataUpdate() {
            if (updateInterval) clearInterval(updateInterval);
            updateInterval = setInterval(fetchDeviceData, 3000); // 每3秒更新一次
        }

        // 从服务器获取共享内存数据
        //  fetchDeviceData()：返回Promise，确保失败后仍能继续定时
        function fetchDeviceData() {
            // 关键：返回整个Promise链
            return fetch(`${API_BASE_URL}?action=get_shmem_data`, {
                method: 'GET',
                credentials: 'include',
                headers: {
                    'Accept': 'application/json',
                    'Cache-Control': 'no-cache' // 新增：禁止浏览器缓存旧数据
                }
            })
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP错误: ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.error) throw new Error(data.error);
                    updateSystemStatus(true);

                    // 1. 处理数据：确保字段不缺失（关键：兼容共享内存可能返回的异常格式）
                    const stm32Data = (data.stm32?.data || []).map(device => ({
                        key: device.key || '',
                        name: device.name || '未知设备',
                        type: device.type || 2,
                        typeStata: device.typeStata || 2,
                        value: device.value ?? 0,
                        floatValue: Number(device.floatValue) || 0.0, // 强制转数字，避免字符串类型
                        addr: device.addr
                    }));
                    deviceData.stm32 = { data: stm32Data };
                    deviceData.modbus = { data: (data.modbus?.data || []).map(d => ({ ...d, floatValue: Number(d.floatValue) || 0.0 })) };
                    deviceData.metaServer = { data: (data.metaServer?.data || []).map(d => ({ ...d, floatValue: Number(d.floatValue) || 0.0 })) };

                    // 2. 强制重新渲染（关键：无论数据是否变化，都重新渲染DOM）
                    renderDevices('stm32');
                    renderDevices('modbus');
                    renderDevices('metaServer');
                    updateStatusCards();
                    updateChartWithNewData();

                    logOperation('共享内存数据更新成功');
                    return data; // 返回数据，方便后续扩展
                })
                .catch(error => {
                    updateSystemStatus(false);
                    const errorMsg = `数据加载失败: ${error.message}`;
                    logOperation(errorMsg);
                    showNotification('数据更新失败', `3秒后重试：${errorMsg}`, 'error');
                    throw error; // 抛出错误，不影响后续定时任务
                });
        }

        // 更新系统状态显示
        function updateSystemStatus(connected) {
            const indicator = document.getElementById('system-status-indicator');
            const mqttStatus = document.getElementById('mqtt-server-status');
            if (connected) {
                indicator.className = 'ml-2 px-2 py-0.5 bg-success/20 text-success text-xs rounded-full flex items-center';
                indicator.innerHTML = '<span class="w-1.5 h-1.5 bg-success rounded-full mr-1 animate-pulse"></span>正常运行中';
                mqttStatus.textContent = '已连接';
            } else {
                indicator.className = 'ml-2 px-2 py-0.5 bg-danger/20 text-danger text-xs rounded-full flex items-center';
                indicator.innerHTML = '<span class="w-1.5 h-1.5 bg-danger rounded-full mr-1 animate-pulse"></span>连接异常';
                mqttStatus.textContent = '连接失败';
            }
        }

        // 更新快速状态卡片（修复：不依赖type，按名称识别温湿度传感器）
        function updateStatusCards() {
            // 统计设备数量
            const stm32Count = deviceData.stm32.data?.length || 0;
            const modbusCount = deviceData.modbus.data?.length || 0;
            const metaServerCount = deviceData.metaServer.data?.length || 0;
            const totalCount = stm32Count + modbusCount + metaServerCount;
            document.getElementById('online-devices').textContent = totalCount;
            document.getElementById('total-devices').textContent = totalCount;

            // 更新温湿度（修复：按名称找传感器，强制读取floatValue并转数字）
            const tempSensor = deviceData.stm32.data.find(d => d.name === '温度传感器');
            const humiSensor = deviceData.stm32.data.find(d => d.name === '湿度传感器');
            if (tempSensor) {
                const tempValue = Number(tempSensor.floatValue) || 0.0;
                document.getElementById('current-temp').textContent = `${tempValue.toFixed(1)}°C`;
            }
            if (humiSensor) {
                const humiValue = Number(humiSensor.floatValue) || 0.0;
                document.getElementById('current-humidity').textContent = `${humiValue.toFixed(0)}%`;
            }

            // 更新警报状态
            const alarmDevice = deviceData.stm32.data.find(d => d.name === '险情警报');
            if (alarmDevice) {
                const status = alarmDevice.value === 0 ? '正常' : '警报中';
                const alarmEl = document.getElementById('alarm-status');
                alarmEl.textContent = status;
                alarmEl.className = status === '警报中' ? 'text-2xl font-bold mt-1 text-danger' : 'text-2xl font-bold mt-1 text-success';
                if (status === '警报中') showNotification('警报提醒', '检测到险情，请注意', 'warning');
            }
        }

        // 渲染设备状态（修复：优先按名称识别温湿度，避免显示开/关）
        function renderDevices(deviceType) {
            const container = document.getElementById(`${deviceType}-devices-container`);
            if (!container) return;
            const devices = deviceData[deviceType]?.data || [];
            container.innerHTML = '';

            if (devices.length === 0) {
                container.innerHTML = `
                    <div class="text-center py-10 text-gray-500">
                        <i class="fa fa-info-circle text-xl mb-2"></i>
                        <p>未获取到${getDeviceTypeName(deviceType)}设备数据</p>
                    </div>
                `;
                return;
            }

            // 为每个设备创建状态卡片（无控制组件）
            devices.forEach(device => {
                const icon = deviceNameIcons[device.name] || 'fa-cog';
                let displayValue = '';

                // 核心修复：优先按设备名称判断温湿度，强制显示数值（不依赖type）
                if (device.name.includes('温度') || device.name.includes('湿度')) {
                    const decimal = device.name.includes('温度') ? 1 : 0; // 温度1位小数，湿度0位
                    const value = Number(device.floatValue) || 0.0; // 强制转数字，避免NaN
                    displayValue = `${value.toFixed(decimal)}`;
                    displayValue += device.name.includes('温度') ? ' °C' : ' %';
                } else if (device.type === 3) {
                    // 其他浮点型设备（如特殊传感器）
                    displayValue = `${(Number(device.floatValue) || 0.0).toFixed(1)}`;
                } else if (device.name === '人体红外检测') {
                    // 红外检测状态
                    displayValue = ['无检测', '检测到人体', '检测到多人'][device.value ?? 0] || '未知状态';
                } else if (device.name === '烟感控制') {
                    // 烟感状态
                    displayValue = device.value === 0 ? '正常' : '报警';
                } else if (device.name === '空调模式') {
                    // 空调模式
                    displayValue = ['未知模式', '制冷', '制热', '除湿'][Math.floor((device.value ?? 0) / 11)] || '未知模式';
                } else if (['窗帘控制', '水产水量控制', '遮阳板控制', '灯光控制'].includes(device.name)) {
                    // 百分比状态设备
                    displayValue = `${device.value ?? 0}%`;
                } else {
                    // 真正的开关型设备（如灯光、插座）
                    displayValue = device.value === 1 ? '开' : '关';
                }

                // 创建设备卡片
                const card = document.createElement('div');
                card.className = 'bg-white rounded-xl p-5 shadow-sm device-card-hover flex flex-col md:flex-row justify-between items-center';
                card.innerHTML = `
                    <div class="flex items-center mb-4 md:mb-0 w-full md:w-auto">
                        <div class="w-12 h-12 rounded-full ${getIconBgColor(device.name)} flex items-center justify-center mr-4">
                            <i class="fa ${icon} ${getIconColor(device.name)} text-xl"></i>
                        </div>
                        <div>
                            <h3 class="font-bold text-gray-800 text-lg">${device.name}</h3>
                            <div class="flex items-center mt-1">
                                <span class="status-indicator ${getDeviceStatusColor(device, displayValue)} mr-2"></span>
                                <p class="text-sm text-gray-600">状态: <span class="${getValueColorClass(device, displayValue)} font-medium">${displayValue}</span></p>
                            </div>
                            <!-- 显示设备key和数据类型(共享内存标识) -->
                            <p class="text-xs text-gray-500 mt-1">
                                标识: ${device.key} | 类型: ${getDataTypeText(device.type)}
                                ${device.addr ? ` | 地址: ${device.addr}` : ''}
                            </p>
                        </div>
                    </div>
                    <!-- 无控制按钮，仅显示状态 -->
                    <div class="w-full md:w-auto text-right text-sm text-gray-500">
                        <span>最后更新: ${new Date().toTimeString().slice(0, 8)}</span>
                    </div>
                `;
                container.appendChild(card);
            });
        }

        // 辅助函数：获取设备类型名称
        function getDeviceTypeName(type) {
            const names = { stm32: 'STM32', modbus: 'Modbus', metaServer: '元服务器' };
            return names[type] || type;
        }

        // 辅助函数：获取数据类型文本
        function getDataTypeText(type) {
            const types = { 1: '布尔型', 2: '整数型', 3: '浮点型' };
            return types[type] || '未知类型';
        }

        // 辅助函数：获取图标背景色
        function getIconBgColor(deviceName) {
            if (deviceName.includes('温度')) return 'bg-primary/10';
            if (deviceName.includes('湿度') || deviceName.includes('水')) return 'bg-secondary/10';
            if (deviceName.includes('电源') || deviceName.includes('灯光')) return 'bg-warning/10';
            if (deviceName.includes('锁') || deviceName.includes('险情') || deviceName.includes('烟感') || deviceName.includes('安检')) return 'bg-danger/10';
            if (deviceName.includes('红外')) return 'bg-info/10';
            return 'bg-primary/10';
        }

        // 辅助函数：获取图标颜色
        function getIconColor(deviceName) {
            if (deviceName.includes('温度')) return 'text-primary';
            if (deviceName.includes('湿度') || deviceName.includes('水')) return 'text-secondary';
            if (deviceName.includes('电源') || deviceName.includes('灯光')) return 'text-warning';
            if (deviceName.includes('锁') || deviceName.includes('险情') || deviceName.includes('烟感') || deviceName.includes('安检')) return 'text-danger';
            if (deviceName.includes('红外')) return 'text-info';
            return 'text-primary';
        }

        // 辅助函数：获取状态指示灯颜色
        function getDeviceStatusColor(device, displayValue) {
            if (device.name === '烟感控制' && displayValue === '报警') return 'bg-danger';
            if (device.name === '险情警报' && displayValue === '警报中') return 'bg-danger';
            if (displayValue === '开' || displayValue === '检测到人体' || displayValue === '检测到多人') return 'bg-success';
            if (displayValue === '关' || displayValue === '无检测') return 'bg-gray-300';
            return 'bg-primary';
        }

        // 辅助函数：获取值颜色样式
        function getValueColorClass(device, displayValue) {
            if (device.name === '烟感控制' && displayValue === '报警') return 'text-danger';
            if (device.name === '险情警报' && displayValue === '警报中') return 'text-danger';
            if (displayValue === '开' || displayValue === '检测到人体' || displayValue === '检测到多人') return 'text-success';
            if (displayValue === '关' || displayValue === '无检测') return 'text-gray-500';
            if (device.name.includes('温度')) {
                const temp = parseFloat(displayValue);
                if (temp > 30) return 'text-danger';
                if (temp < 10) return 'text-blue-500';
            }
            return 'text-gray-800';
        }

        // 更新图表数据（用共享内存最新数据）
        function updateChartWithNewData() {
            if (!tempHumidityChart) return;
            const tempSensor = deviceData.stm32.data.find(d => d.name === '温度传感器');
            const humiSensor = deviceData.stm32.data.find(d => d.name === '湿度传感器');
            if (!tempSensor || !humiSensor) return;

            const option = tempHumidityChart.getOption();
            const now = new Date();
            const hour = now.getHours().toString().padStart(2, '0');
            const minute = now.getMinutes().toString().padStart(2, '0');
            const currentTime = `${hour}:${minute}`;
            const lastTime = option.xAxis[0].data[option.xAxis[0].data.length - 1];

            if (lastTime !== currentTime) {
                // 添加最新数据点（强制转数字）
                const tempValue = Number(tempSensor.floatValue) || 0.0;
                const humiValue = Number(humiSensor.floatValue) || 0.0;
                option.xAxis[0].data.push(currentTime);
                option.series[0].data.push(tempValue.toFixed(1));
                option.series[1].data.push(humiValue.toFixed(0));

                // 保持数据点数量
                if (option.xAxis[0].data.length > 60) {
                    option.xAxis[0].data.shift();
                    option.series[0].data.shift();
                    option.series[1].data.shift();
                }
                tempHumidityChart.setOption(option);
            }
        }

        // 监控画面相关函数
        function monitorLoaded() {
            document.getElementById('monitor-loading').classList.add('hidden');
            document.getElementById('monitor-status').textContent = '实时监控';
            document.getElementById('monitor-status').parentElement.querySelector('.status-indicator').className = 'status-indicator bg-success mr-1';
        }

        function monitorError() {
            document.getElementById('monitor-loading').innerHTML = `
                <div class="text-center">
                    <i class="fa fa-exclamation-circle text-2xl text-danger mb-2"></i>
                    <p class="text-sm text-danger">监控画面加载失败</p>
                    <p class="text-xs text-gray-600 mt-1">请检查设备连接或点击刷新</p>
                </div>
            `;
            document.getElementById('monitor-status').textContent = '连接失败';
            document.getElementById('monitor-status').parentElement.querySelector('.status-indicator').className = 'status-indicator bg-danger mr-1';
        }

        function refreshMonitor() {
            const iframe = document.getElementById('monitor-iframe');
            const currentSrc = iframe.src;
            document.getElementById('monitor-loading').classList.remove('hidden');
            document.getElementById('monitor-loading').innerHTML = `
                <div class="text-center">
                    <i class="fa fa-circle-o-notch fa-spin text-2xl text-gray-600 mb-2"></i>
                    <p class="text-sm text-gray-600">监控画面刷新中...</p>
                </div>
            `;
            iframe.src = '';
            setTimeout(() => iframe.src = currentSrc, 300);
            logOperation('监控画面已刷新');
        }

        function switchCamera(url) {
            const iframe = document.getElementById('monitor-iframe');
            document.getElementById('monitor-loading').classList.remove('hidden');
            document.getElementById('monitor-loading').innerHTML = `
                <div class="text-center">
                    <i class="fa fa-circle-o-notch fa-spin text-2xl text-gray-600 mb-2"></i>
                    <p class="text-sm text-gray-600">切换摄像头中...</p>
                </div>
            `;
            iframe.src = url;
            logOperation(`切换摄像头至: ${url}`);
        }

        // 通知函数
        function showNotification(title, message, type = 'success') {
            const notification = document.getElementById('notification');
            const iconEl = document.getElementById('notification-icon');
            iconEl.className = 'w-8 h-8 rounded-full flex items-center justify-center mr-3';
            document.getElementById('notification-title').textContent = title;
            document.getElementById('notification-message').textContent = message;

            switch (type) {
                case 'success': iconEl.className += ' bg-success/10 text-success'; iconEl.innerHTML = '<i class="fa fa-check"></i>'; break;
                case 'error': iconEl.className += ' bg-danger/10 text-danger'; iconEl.innerHTML = '<i class="fa fa-times"></i>'; break;
                case 'warning': iconEl.className += ' bg-warning/10 text-warning'; iconEl.innerHTML = '<i class="fa fa-exclamation-triangle"></i>'; break;
                case 'info': iconEl.className += ' bg-info/10 text-info'; iconEl.innerHTML = '<i class="fa fa-info-circle"></i>'; break;
            }
            notification.classList.remove('translate-x-full');
            setTimeout(hideNotification, 3000);
        }

        function hideNotification() {
            document.getElementById('notification').classList.add('translate-x-full');
        }

        // 日志函数
        function logOperation(message) {
            const logContainer = document.getElementById('operation-log');
            const now = new Date();
            const timeStr = now.toTimeString().slice(0, 8);
            const logItem = document.createElement('div');
            logItem.className = 'text-sm text-gray-500 mb-2 animate-fadeIn';
            logItem.innerHTML = `<span class="text-gray-400">[${timeStr}]</span> ${message}`;
            logContainer.prepend(logItem);
            if (logContainer.children.length > 50) logContainer.removeChild(logContainer.lastChild);
        }

        // 页面卸载清理
        window.addEventListener('beforeunload', function () {
            if (updateInterval) clearInterval(updateInterval);
        });
    </script>
</body>

</html>